package ucl.cs.stockBroker.client;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Scanner;

import ucl.cs.stockBroker.common.Account;
import ucl.cs.stockBroker.common.AccountInfo;
import ucl.cs.stockBroker.common.Stock;
import ucl.cs.stockBroker.common.StockBroker;
import ucl.cs.stockBroker.exceptions.InsufficientFundsException;
import ucl.cs.stockBroker.exceptions.InsufficientStocksException;
import ucl.cs.stockBroker.exceptions.InvalidPinException;
import ucl.cs.stockBroker.exceptions.InvalidStockException;
import ucl.cs.stockBroker.exceptions.NoSuchAccountException;

public class Client {

	enum Options {
		HELP, CREATEACCOUNT, TERMINATEACCOUNT, LISTACCOUNTS, ACCOUNTINFO, BUYSTOCKS, SELLSTOCKS, LISTSTOCKS, QUIT
	};

	public static void main(String[] args) {

		try {
			String host = args[0];
			int port = Integer.parseInt(args[1]);

			Registry registry = LocateRegistry.getRegistry(host, port);
			StockBroker stockBroker = (StockBroker) registry.lookup("Server");

			printHelp();
			System.out.println("\n>> Please enter your selection: ");
			String input = getInput();
			selectOption(input, stockBroker);
		} catch (ArrayIndexOutOfBoundsException e) {
			printCorrectUsage();
			System.exit(1);
		} catch (java.rmi.RemoteException re) {
			System.out.println();
			System.out.println("RemoteException");
			System.out.println(re);
		} catch (java.rmi.NotBoundException nbe) {
			System.out.println();
			System.out.println("NotBoundException");
			System.out.println(nbe);
		}
	}

	private static void selectOption(String input, StockBroker stockBroker) {
		String[] stringArray = input.split(" ");
		try {
			Options options = Options.valueOf(stringArray[0].toUpperCase());
			switch (options) {
			case CREATEACCOUNT:
				if (stringArray.length != 3) {
					printUsage();
				} else {
					createAccount(stringArray[1], stringArray[2], stockBroker);
				}
				break;
			case TERMINATEACCOUNT:
				if (stringArray.length != 3) {
					printUsage();
				} else {
					terminateAccount(stringArray[1], stringArray[2],
							stockBroker);
				}
				break;
			case LISTACCOUNTS:
				if (stringArray.length != 1) {
					printUsage();
				} else {
					listAccounts(stockBroker);
				}
				break;
			case ACCOUNTINFO:
				if (stringArray.length != 3) {
					printUsage();
				} else {
					accountInfo(stringArray[1], stringArray[2], stockBroker);
				}
				break;
			case BUYSTOCKS:
				if (stringArray.length != 5) {
					printUsage();
				} else {
					buyStocks(stringArray[1], stringArray[2], stringArray[3],
							stringArray[4], stockBroker);
				}
				break;
			case SELLSTOCKS:
				if (stringArray.length != 5) {
					printUsage();
				} else {
					sellStocks(stringArray[1], stringArray[2], stringArray[3],
							stringArray[4], stockBroker);
				}
				break;
			case LISTSTOCKS:
				if (stringArray.length != 1) {
					printUsage();
				} else {
					listStocks(stockBroker);
				}
				break;
			case QUIT:
				if (stringArray.length != 1) {
					printUsage();
				} else {
					System.out.println("\n>> System is now Quitting <<");
					System.exit(1);
				}
				break;
			case HELP:
				printHelp();
				break;
			default:
				System.out.println("\n>> Invalid selection");
				break;
			}

		} catch (InvalidPinException e) {
			System.out.println("\n>> Invalid PIN. Please try again.");
		} catch (InsufficientFundsException ae) {
			System.out.println("\n>> Insufficient Funds Available");
		} catch (InvalidStockException e) {
			System.out.println("\n>> No Such Stock Available");
		} catch (InsufficientStocksException e) {
			System.out.println("\n>> Insufficient Stocks");
		} catch (NoSuchAccountException except) {
			System.out.println("\n>> No such account. Please try again");
		} catch (java.rmi.RemoteException re) {
			System.out.println();
			System.out.println("RemoteException");
			System.out.println(re);
		} catch (IllegalArgumentException e) {
			invalidSelection();
		} finally {
			System.out.println("\n>> Please enter your selection: ");
			reEntry(stockBroker);
		}
	}

	private static void invalidSelection() {
		System.out.println("\n>> Invalid selection. Please try again");
		System.out.println(">> Print help? <Y/N> : ");
		String answer = getInput().toUpperCase();
		if (answer.equals("Y") || answer.equals("YES")) {
			printHelp();
		} else if (answer.equals("N") || answer.equals("NO")) {
		} else {
			invalidSelection();
		}
	}

	private static String getInput() {
		Scanner in = new Scanner(System.in);
		String input = in.nextLine();
		return input;
	}

	private static String getPIN(String input) throws InvalidPinException {
		String pin = null;
		try {
			pin = input;
		} catch (NumberFormatException nfe) {
			throw new InvalidPinException(
					"Invalid PIN. Please try again. PIN must be 4 digits long");
		}
		return pin;
	}

	private static void reEntry(StockBroker stockBroker) {
		String myInput = getInput();
		selectOption(myInput, stockBroker);
	}

	private static void createAccount(String accountName, String pin,
			StockBroker stockBroker) throws RemoteException, InvalidPinException {
		pin = getPIN(pin);
		int account_number = stockBroker.createAccount(accountName, pin);
		System.out.println(">> Created account number : " + account_number);
	}

	private static void terminateAccount(String accountNumber, String pin,
			StockBroker stockBroker) throws RemoteException, NoSuchAccountException, InvalidPinException {
		pin = getPIN(pin);
		int account_number = Integer.parseInt(accountNumber);
		float accountValue = stockBroker.terminateAccount(account_number, pin);
		System.out.println(">> Terminated account number: " + account_number);
		if (accountValue < 0) {
			System.out.println(">> Account in debt by: " + accountValue);
		} else {
			System.out.println(">> Account in credit by: " + accountValue);
		}
	}

	private static void listStocks(StockBroker stockBroker) throws RemoteException {
		System.out.println("\n>> Symbol---Name---Price");
		System.out.println("-------------------------------\n");
		Stock[] stocks = stockBroker.listStocks();
		for (Stock stock : stocks) {
			System.out.println(">> " + stock.getSymbol() + "--"
					+ stock.getName() + "--" + stock.getPrice());
		}
	}

	private static void listAccounts(StockBroker stockBroker) throws RemoteException, NoSuchAccountException {
		AccountInfo[] info_array = stockBroker.listAccounts();
		for (int i = 0; i < info_array.length; i++) {
			System.out.println(">> " + info_array[i]); // should this be
														// info_array[i].toString();
		}
		if (info_array.length == 0) {
			System.out.println(">> No Accounts found in the system.");
		}
	}

	private static void sellStocks(String accountNumber, String pin,
			String companySymbol, String units, StockBroker stockBroker) throws RemoteException, NoSuchAccountException, InvalidPinException, InsufficientStocksException, InvalidStockException {
		int account_number = Integer.parseInt(accountNumber);
		pin = getPIN(pin);
		int unitsOfStock = Integer.parseInt(units);
		stockBroker.sellStocks(account_number, pin,
				companySymbol.toUpperCase(), unitsOfStock);
		System.out.println(">> Sold successfully. Sold " + unitsOfStock
				+ " stocks of " + companySymbol);
	}

	private static void buyStocks(String accountNumber, String pin,
			String companySymbol, String units, StockBroker stockBroker) throws RemoteException, NoSuchAccountException, InvalidPinException, InsufficientFundsException, InvalidStockException {
		int account_number = Integer.parseInt(accountNumber);
		pin = getPIN(pin);
		int unitsOfStock = Integer.parseInt(units);
		stockBroker.buyStocks(account_number, pin, companySymbol.toUpperCase(),
				unitsOfStock);
		System.out.println(">> Purchase successful. Bought " + unitsOfStock
				+ " stocks of " + companySymbol);
	}

	private static void accountInfo(String accountNumber, String pin,
			StockBroker stockBroker) throws RemoteException, NoSuchAccountException, InvalidPinException {
		int account_number = Integer.parseInt(accountNumber);
		Account account = stockBroker.getAccount(account_number, pin);
		String info = account.getDescription();
		System.out.println(">> " + info);
	}

	private static void printCorrectUsage() {
		System.out.println("\n>> Incorrect Syntax.");
		System.out.println(">> Correct Usage: IP/Hostname Port");
		System.out.println(">> Please try again");
	}

	private static void printUsage() {
		System.out.println("\n>> Incorrect Usage. Please use as follows: ");
		System.out.println(">> usage: createaccount <account_name> <PIN>");
		System.out.println(">> usage: terminateaccount <account_number> <PIN>");
		System.out.println(">> usage: accountinfo   <account_number> <PIN>");
		System.out.println(">> usage: listaccounts");
		System.out.println(">> usage: liststocks");
		System.out
				.println(">> usage: buystocks <account_number> <PIN> <Company Symbol> <Units of stock>");
		System.out
				.println(">> usage: sellstocks <account_number> <PIN> <Company Symbol> <Units of stock>");
		System.out.println(">> usage: quit");
	}

	private static void printHelp() {
		System.out.println("\n>> List of commands and usage");
		System.out.println(">> -----------------------------");
		System.out.println(">> usage: createaccount <account_name> <PIN>");
		System.out
				.println(">> usage: terminateeaccount <account_number> <PIN>");
		System.out.println(">> usage: accountinfo   <account_number> <PIN>");
		System.out.println(">> usage: listaccounts");
		System.out.println(">> usage: liststocks");
		System.out
				.println(">> usage: buystocks <account_number> <PIN> <Company Symbol> <Units of stock>");
		System.out
				.println(">> usage: sellstocks <account_number> <PIN> <Company Symbol> <Units of stock>");
		System.out.println(">> usage: quit");
	}

}
